package wiki.xsx.core.handler;

import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import wiki.xsx.core.util.ApplicationContextUtil;

import java.util.concurrent.ConcurrentMap;

/**
 * 通用助手
 * @author xsx
 * @date 2019/4/25
 * @since 1.8
 */
public class CommonHandler {
    /**
     * 通用助手实例
     */
    private static final CommonHandler HANDLER = new CommonHandler();
    /**
     * 助手管理实例
     */
    private static final HandlerManager MANAGER = HandlerManager.getManager();

    /**
     * 通用助手构造
     */
    private CommonHandler() {
        int dbIndex = getInitDBIndex();
        initDBHandler(dbIndex);
        initKeyHandler(dbIndex);
        initNumberHandler(dbIndex);
        initStringHandler(dbIndex);
        initListHandler(dbIndex);
        initHashHandler(dbIndex);
        initSetHandler(dbIndex);
        initZsetHandler(dbIndex);
        initBitmapHandler(dbIndex);
        initGeoHandler(dbIndex);
        initHyperLogLogHandler(dbIndex);
        initScriptHandler(dbIndex);
        initPubSubHandler(dbIndex);
        initSentinelHandler(dbIndex);
    }

    /**
     * 获取助手实例
     * @return 返回助手实例
     */
    public static CommonHandler getInstance() {
        return HANDLER;
    }

    /**
     * 获取默认KEY
     * @return 返回默认KEY
     */
    public String getDefaultKey() {
        return MANAGER.getDefaultKey();
    }

    /**
     * 获取数据库助手
     * @param key KEY
     * @return 返回数据库助手
     */
    public DBHandler getDBHandler(String key) {
        ConcurrentMap<String, DBHandler> dbMap = MANAGER.getDbMap();
        DBHandler handler = dbMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = dbMap.get(key);
            if (handler==null) {
                DBHandler instance = DBHandler.getInstance(Integer.valueOf(key));
                handler = dbMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取键助手
     * @param key KEY
     * @return 返回键助手
     */
    public KeyHandler getKeyHandler(String key) {
        ConcurrentMap<String, KeyHandler> keyMap = MANAGER.getKeyMap();
        KeyHandler handler = keyMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = keyMap.get(key);
            if (handler==null) {
                KeyHandler instance = KeyHandler.getInstance(Integer.valueOf(key));
                handler = keyMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取数字助手
     * @param key KEY
     * @return 返回数字助手
     */
    public NumberHandler getNumberHandler(String key) {
        ConcurrentMap<String, NumberHandler> numberMap = MANAGER.getNumberMap();
        NumberHandler handler = numberMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = numberMap.get(key);
            if (handler==null) {
                NumberHandler instance = NumberHandler.getInstance(Integer.valueOf(key));
                handler = numberMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取字符串助手
     * @param key KEY
     * @return 返回字符串助手
     */
    public StringHandler getStringHandler(String key) {
        ConcurrentMap<String, StringHandler> stringMap = MANAGER.getStringMap();
        StringHandler handler = stringMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = stringMap.get(key);
            if (handler==null) {
                StringHandler instance = StringHandler.getInstance(Integer.valueOf(key));
                handler = stringMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取列表助手
     * @param key KEY
     * @return 返回列表助手
     */
    public ListHandler getListHandler(String key) {
        ConcurrentMap<String, ListHandler> listMap = MANAGER.getListMap();
        ListHandler handler = listMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = listMap.get(key);
            if (handler==null) {
                ListHandler instance = ListHandler.getInstance(Integer.valueOf(key));
                handler = listMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取哈希助手
     * @param key KEY
     * @return 返回哈希助手
     */
    public HashHandler getHashHandler(String key) {
        ConcurrentMap<String, HashHandler> hashMap = MANAGER.getHashMap();
        HashHandler handler = hashMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = hashMap.get(key);
            if (handler==null) {
                HashHandler instance = HashHandler.getInstance(Integer.valueOf(key));
                handler = hashMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取无序集合助手
     * @param key KEY
     * @return 返回无序集合助手
     */
    public SetHandler getSetHandler(String key) {
        ConcurrentMap<String, SetHandler> setMap = MANAGER.getSetMap();
        SetHandler handler = setMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = setMap.get(key);
            if (handler==null) {
                SetHandler instance = SetHandler.getInstance(Integer.valueOf(key));
                handler = setMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取有序集合助手
     * @param key KEY
     * @return 返回有序集合助手
     */
    public ZsetHandler getZsetHandler(String key) {
        ConcurrentMap<String, ZsetHandler> zsetMap = MANAGER.getZsetMap();
        ZsetHandler handler = zsetMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = zsetMap.get(key);
            if (handler==null) {
                ZsetHandler instance = ZsetHandler.getInstance(Integer.valueOf(key));
                handler = zsetMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取位图助手
     * @param key KEY
     * @return 返回位图助手
     */
    public BitmapHandler getBitmapHandler(String key) {
        ConcurrentMap<String, BitmapHandler> bitmapMap = MANAGER.getBitmapMap();
        BitmapHandler handler = bitmapMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = bitmapMap.get(key);
            if (handler==null) {
                BitmapHandler instance = BitmapHandler.getInstance(Integer.valueOf(key));
                handler = bitmapMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取地理位置助手
     * @param key KEY
     * @return 返回地理位置助手
     */
    public GeoHandler getGeoHandler(String key) {
        ConcurrentMap<String, GeoHandler> geoMap = MANAGER.getGeoMap();
        GeoHandler handler = geoMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = geoMap.get(key);
            if (handler==null) {
                GeoHandler instance = GeoHandler.getInstance(Integer.valueOf(key));
                handler = geoMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取基数助手
     * @param key KEY
     * @return 返回基数助手
     */
    public HyperLogLogHandler getHyperLogLogHandler(String key) {
        ConcurrentMap<String, HyperLogLogHandler> hyperLogLogMap = MANAGER.getHyperLogLogMap();
        HyperLogLogHandler handler = hyperLogLogMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = hyperLogLogMap.get(key);
            if (handler==null) {
                HyperLogLogHandler instance = HyperLogLogHandler.getInstance(Integer.valueOf(key));
                handler = hyperLogLogMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取lua脚本助手
     * @param key KEY
     * @return 返回lua脚本助手
     */
    public ScriptHandler getScriptHandler(String key) {
        ConcurrentMap<String, ScriptHandler> scriptMap = MANAGER.getScriptMap();
        ScriptHandler handler = scriptMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = scriptMap.get(key);
            if (handler==null) {
                ScriptHandler instance = ScriptHandler.getInstance(Integer.valueOf(key));
                handler = scriptMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取发布订阅助手
     * @param key KEY
     * @return 返回发布订阅助手
     */
    public PubSubHandler getPubSubHandler(String key) {
        ConcurrentMap<String, PubSubHandler> pubSubMap = MANAGER.getPubSubMap();
        PubSubHandler handler = pubSubMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = pubSubMap.get(key);
            if (handler==null) {
                PubSubHandler instance = PubSubHandler.getInstance(Integer.valueOf(key));
                handler = pubSubMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取分布式锁助手
     * @param key KEY
     * @return 返回分布式锁助手
     */
    public RedisLockHandler getRedisLockHandler(String key) {
        ConcurrentMap<String, RedisLockHandler> lockMap = MANAGER.getLockMap();
        RedisLockHandler handler = lockMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = lockMap.get(key);
            if (handler==null) {
                int dbIndex = Integer.valueOf(key);
                if (lockMap.size()==0) {
                    initRedisLockHandler(dbIndex);
                }
                RedisLockHandler instance = RedisLockHandler.getInstance(dbIndex);
                handler = lockMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取哨兵助手
     * @param key KEY
     * @return 返回哨兵助手
     */
    public SentinelHandler getSentinelHandler(String key) {
        ConcurrentMap<String, SentinelHandler> sentinelMap = MANAGER.getSentinelMap();
        SentinelHandler handler = sentinelMap.get(key);
        if (handler!=null) {
            return handler;
        }
        synchronized (MANAGER) {
            handler = sentinelMap.get(key);
            if (handler==null) {
                SentinelHandler instance = SentinelHandler.getInstance(Integer.valueOf(key));
                handler = sentinelMap.putIfAbsent(key, instance);
                if (handler==null) {
                    handler = instance;
                }
            }
        }
        return handler;
    }

    /**
     * 获取集群助手
     * @return 返回集群助手
     */
    public ClusterHandler getClusterHandler() {
        return MANAGER.getClusterHandler();
    }

    /**
     * 获取默认对象模板
     * @return 返回对象模板
     */
    public RedisTemplate<String, Object> getDefaultRedisTemplate() {
        return HandlerManager.getDefaultRedisTemplate();
    }

    /**
     * 获取默认字符串模板
     * @return 返回字符串模板
     */
    public StringRedisTemplate getDefaultStringRedisTemplate() {
        return HandlerManager.getDefaultStringRedisTemplate();
    }

    /**
     * 获取初始化数据库索引
     * @return 返回数据库索引
     */
    private int getInitDBIndex() {
        return ApplicationContextUtil.getContext().getBean(RedisProperties.class).getDatabase();
    }

    /**
     * 初始化数据库助手
     * @param dbIndex 数据库索引
     */
    private void initDBHandler(int dbIndex) {
        ConcurrentMap<String, DBHandler> dbMap = MANAGER.getDbMap();
        DBHandler handler = DBHandler.getInstance(dbIndex);
        dbMap.put(getDefaultKey(), handler);
        dbMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化键助手
     * @param dbIndex 数据库索引
     */
    private void initKeyHandler(int dbIndex) {
        ConcurrentMap<String, KeyHandler> keyMap = MANAGER.getKeyMap();
        KeyHandler handler = KeyHandler.getInstance(dbIndex);
        keyMap.put(getDefaultKey(), handler);
        keyMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化数字助手
     * @param dbIndex 数据库索引
     */
    private void initNumberHandler(int dbIndex) {
        ConcurrentMap<String, NumberHandler> stringMap = MANAGER.getNumberMap();
        NumberHandler handler = NumberHandler.getInstance(dbIndex);
        stringMap.put(getDefaultKey(), handler);
        stringMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化字符串助手
     * @param dbIndex 数据库索引
     */
    private void initStringHandler(int dbIndex) {
        ConcurrentMap<String, StringHandler> stringMap = MANAGER.getStringMap();
        StringHandler handler = StringHandler.getInstance(dbIndex);
        stringMap.put(getDefaultKey(), handler);
        stringMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化列表助手
     * @param dbIndex 数据库索引
     */
    private void initListHandler(int dbIndex) {
        ConcurrentMap<String, ListHandler> listMap = MANAGER.getListMap();
        ListHandler handler = ListHandler.getInstance(dbIndex);
        listMap.put(getDefaultKey(), handler);
        listMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化哈希助手
     * @param dbIndex 数据库索引
     */
    private void initHashHandler(int dbIndex) {
        ConcurrentMap<String, HashHandler> hashMap = MANAGER.getHashMap();
        HashHandler handler = HashHandler.getInstance(dbIndex);
        hashMap.put(getDefaultKey(), handler);
        hashMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化无序集合助手
     * @param dbIndex 数据库索引
     */
    private void initSetHandler(int dbIndex) {
        ConcurrentMap<String, SetHandler> setMap = MANAGER.getSetMap();
        SetHandler handler = SetHandler.getInstance(dbIndex);
        setMap.put(getDefaultKey(), handler);
        setMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化有序集合助手
     * @param dbIndex 数据库索引
     */
    private void initZsetHandler(int dbIndex) {
        ConcurrentMap<String, ZsetHandler> zsetMap = MANAGER.getZsetMap();
        ZsetHandler handler = ZsetHandler.getInstance(dbIndex);
        zsetMap.put(getDefaultKey(), handler);
        zsetMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化位图助手
     * @param dbIndex 数据库索引
     */
    private void initBitmapHandler(int dbIndex) {
        ConcurrentMap<String, BitmapHandler> bitmapMap = MANAGER.getBitmapMap();
        BitmapHandler handler = BitmapHandler.getInstance(dbIndex);
        bitmapMap.put(getDefaultKey(), handler);
        bitmapMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化地理位置助手
     * @param dbIndex 数据库索引
     */
    private void initGeoHandler(int dbIndex) {
        ConcurrentMap<String, GeoHandler> geoMap = MANAGER.getGeoMap();
        GeoHandler handler = GeoHandler.getInstance(dbIndex);
        geoMap.put(getDefaultKey(), handler);
        geoMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化基数助手
     * @param dbIndex 数据库索引
     */
    private void initHyperLogLogHandler(int dbIndex) {
        ConcurrentMap<String, HyperLogLogHandler> hyperLogLogMap = MANAGER.getHyperLogLogMap();
        HyperLogLogHandler handler = HyperLogLogHandler.getInstance(dbIndex);
        hyperLogLogMap.put(getDefaultKey(), handler);
        hyperLogLogMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化lua脚本助手
     * @param dbIndex 数据库索引
     */
    private void initScriptHandler(int dbIndex) {
        ConcurrentMap<String, ScriptHandler> scriptMap = MANAGER.getScriptMap();
        ScriptHandler handler = ScriptHandler.getInstance(dbIndex);
        scriptMap.put(getDefaultKey(), handler);
        scriptMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化发布订阅助手
     * @param dbIndex 数据库索引
     */
    private void initPubSubHandler(int dbIndex) {
        ConcurrentMap<String, PubSubHandler> pubSubMap = MANAGER.getPubSubMap();
        PubSubHandler handler = PubSubHandler.getInstance(dbIndex);
        pubSubMap.put(getDefaultKey(), handler);
        pubSubMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化分布式锁助手
     * @param dbIndex 数据库索引
     */
    private void initRedisLockHandler(int dbIndex) {
        ConcurrentMap<String, RedisLockHandler> lockMap = MANAGER.getLockMap();
        RedisLockHandler handler = RedisLockHandler.getInstance();
        lockMap.put(getDefaultKey(), handler);
        lockMap.put(String.valueOf(dbIndex), handler);
    }

    /**
     * 初始化哨兵助手
     * @param dbIndex 数据库索引
     */
    private void initSentinelHandler(int dbIndex) {
        ConcurrentMap<String, SentinelHandler> sentinelMap = MANAGER.getSentinelMap();
        SentinelHandler handler = SentinelHandler.getInstance(dbIndex);
        sentinelMap.put(getDefaultKey(), handler);
        sentinelMap.put(String.valueOf(dbIndex), handler);
    }

}
